package com.ww.exercise.channel.channels

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.time.LocalDateTime
import java.util.concurrent.ConcurrentHashMap
import kotlin.coroutines.coroutineContext

// 服务实例数据类
data class ServiceInstance(
    val id: String,
    val host: String,
    val port: Int,
    val checkIntervalMs: Long = 5000,
    val timeoutMs: Long = 2000 // 超时时间，默认2秒
)

// 服务健康状态
sealed class HealthStatus {
    data class Healthy(
        val service: ServiceInstance,
        val checkedAt: LocalDateTime = LocalDateTime.now()
    ) : HealthStatus()

    data class Unhealthy(
        val service: ServiceInstance,
        val reason: String,
        val checkedAt: LocalDateTime = LocalDateTime.now()
    ) : HealthStatus()

    data class Unknown(
        val service: ServiceInstance
    ) : HealthStatus()
}

// 健康检查接口
interface HealthChecker {
    // 用于接收健康状态变化的通道
    val statusChannel: Channel<HealthStatus>

    // 添加服务实例进行监控
    suspend fun addService(service: ServiceInstance)

    // 移除服务实例进行监控
    suspend fun removeService(serviceId: String)

    // 启动健康检查器
    fun start()

    // 停止健康检查器
    fun stop()
}

class ServiceHealthyChecker(
    private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO)
) : HealthChecker {

    override val statusChannel = Channel<HealthStatus>(Channel.BUFFERED)

    // 存储服务实例及其对应的检查协程
    private val services = ConcurrentHashMap<String, Pair<ServiceInstance, Job>>()
    private val mutex = Mutex()
    private var isRunning = false

    override suspend fun addService(service: ServiceInstance) {
        mutex.withLock {
            if (services.containsKey(service.id)) {
                // 服务已存在，先取消其检查任务
                services[service.id]?.second?.cancel()
            }

            // 创建并启动检查协程
            val checkJob = scope.launch {
                performHealthyChecks(service)
            }

            services[service.id] = service to checkJob
            // 初始状态设置为未知
            statusChannel.send(HealthStatus.Unknown(service))
        }
    }

    override suspend fun removeService(serviceId: String) {
        mutex.withLock {
            services.remove(serviceId)?.second?.cancel()
        }
    }

    override fun start() {
        isRunning = true
    }

    override fun stop() {
        isRunning = false
        scope.cancel()
        statusChannel.close()
    }

    // 执行健康检查的协程
    private suspend fun performHealthyChecks(service: ServiceInstance) {
        while (isRunning && coroutineContext.isActive) {
            try {
                // 执行健康检查，带超时机制
                val isHealthy = withTimeout(service.timeoutMs) {
                    checkServiceHealth(service)
                }

                val newStatus = if (isHealthy) {
                    HealthStatus.Healthy(service)
                } else {
                    HealthStatus.Unhealthy(service, "健康检查失败")
                }

                statusChannel.send(newStatus)
            } catch (e: TimeoutCancellationException) {
                statusChannel.send(HealthStatus.Unhealthy(service, "检查过程发生错误：${e.message ?: e.toString()}"))
            }

            // 等待下一次检查
            delay(service.checkIntervalMs)
        }
    }

    // 模拟实现，实际应用中应替换为真实的健康检查逻辑
    private suspend fun checkServiceHealth(service: ServiceInstance): Boolean {
        return withContext(Dispatchers.IO) {
            kotlin.random.Random.nextDouble() > 0.3
        }
    }
}

suspend fun main() {
    // 创建健康检查器
    val healthChecker = ServiceHealthyChecker()

    // 启动健康检查器
    healthChecker.start()

    // 启动一个协程来接收状态变化
    val statusReceiverJob = CoroutineScope(Dispatchers.IO).launch {
        healthChecker.statusChannel.consumeEach { status ->
            when (status) {
                is HealthStatus.Healthy ->
                    println("${status.checkedAt} - 服务 ${status.service.id} 健康")

                is HealthStatus.Unhealthy ->
                    println("${status.checkedAt} - 服务 ${status.service.id} 不健康：${status.reason}")

                is HealthStatus.Unknown ->
                    println("服务 ${status.service.id} 开始监控，初始状态未知")
            }
        }
    }

    // 添加几个服务实例
    healthChecker.addService(ServiceInstance("service-1", "localhost", 8080))
    healthChecker.addService(ServiceInstance("service-2", "localhost", 8090, 3000))
    healthChecker.addService(ServiceInstance("service-3", "localhost", 8010, 7000, 3000))

    delay(20000)

    println("移除service-2的监控")
    healthChecker.removeService("service-2")

    // 再运行一段时间
    delay(50000)

    // 添加一个服务
    healthChecker.addService(ServiceInstance("service-4", "localhost", 8083))

    // 再运行一段时间
    delay(10000)

    // 停止监控检查
    healthChecker.stop()
    statusReceiverJob.join()
}